/**
* @file EngineMath.cpp
*
* @author Bobak Manavi (BM)
*/

#include "EngineMath.h"



//////////////////////////////////////////////////////////////////////////
// Common math functions
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
// General Utility functions
//////////////////////////////////////////////////////////////////////////

// Are two floating point numbers equal to each other
// Floating Point Error Safe
//
// IN:		a		The first number
//			b		The second number
//
// RETURN: TRUE iff |a-b| < Tolerance
//
// NOTE:	EPSILON is tolerance
bool IsEqual(float a, float b)
{
	// NOTE: Do not modify.
	return fabs(a - b) < EPSILON;
}

// Is a floating point value equal to zero
// Floating Point Error Safe
//
// IN:		a		The number to check
//
// RETURN:	TRUE iff |a| < Tolerance
//
// NOTE:	Tolerance set by EPSILON
bool IsZero(float a)
{
	// NOTE: Do not modify
	return (fabs(a))<EPSILON;
}

// RETURN: MAX of two numbers
float Max(float a, float b)
{
	// NOTE: Do not modify.
	return (a > b) ? a : b;
}

// RETURN: MIN of two numbers
float Min(float a, float b)
{
	// NOTE: Do not modify.
	return (a < b) ? a : b;
}

// RETURN: Converts input to radian measure
float Degrees_To_Radians(float Deg)
{
	// NOTE: Do not modify.
	return Deg * PI / 180.0f;
}

// RETURN: Converts input to degree measure
float Radians_To_Degrees(float Rad)
{
	// NOTE: Do not modify.
	return Rad * 180.0f / PI;
}
////////////////////////////////////////////////////////////////////////
// Linear Algebra Functions Day 1
///////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// Vector Functions
//////////////////////////////////////////////////////////////////////////

// Check if two TVECTOR's are equal to each other
//
// IN:		v		First Vector
//			w		Second Vector
//
// RETURN:  True if v==w, False otherwise
//
// NOTE:	Use's all four components
//			Should be floating point error safe.
bool Vector_IsEqual(TVECTOR v, TVECTOR w)
{
	// TODO LAB 1: Replace with your implementation.
	if (IsEqual(v.x,w.x)&& IsEqual(v.y,w.y)&& IsEqual(v.z,w.z))
		return true;
	return false;
}

// ADD two TVECTOR's togother
//
// IN:		v		First Vector. Left Hand Side
//			w		Second Vector. Right Hand Side
//
// RETURN:  v + w
//
// NOTE:	Use's all four components
TVECTOR Vector_Add(TVECTOR v, TVECTOR w)
{
	// TODO LAB 1: Replace with your implementation.
	TVECTOR Temp;
	Temp.x = (v.x + w.x);
	Temp.y = (v.y + w.y);
	Temp.z = (v.z + w.z);
	Temp.w = (v.w + w.w);
	return Temp;
}

// SUBTRACT one TVECTOR from another
//
// IN:		v		First Vector. Left Hand Side
//			w		Second Vector. Right Hand Side
//
// RETURN:  v - w
//
// NOTE:	Use's all four components
TVECTOR Vector_Sub(TVECTOR v, TVECTOR w)
{
	// TODO LAB 1: Replace with your implementation.
	TVECTOR Temp;
	Temp.x = (v.x - w.x);
	Temp.y = (v.y - w.y);
	Temp.z = (v.z - w.z);
	Temp.w = (v.w - w.w);
	return Temp;
}

// MULTIPLY all four components of a TVECTOR by a scalar
//
// IN:		v		The vector to scale
//			s		The value to scale by
//
// RETURN:  s * v
TVECTOR Vector_Scalar_Multiply(TVECTOR v, float s)
{
	// TODO LAB 1: Replace with your implementation.
	TVECTOR Temp;
	Temp.x = (v.x * s);
	Temp.y = (v.y * s);
	Temp.z = (v.z * s);
	Temp.w = (v.w * s);
	return Temp; 
}

// NEGATE all the components of a TVECTOR
//
// IN:		v		The vector to negate
//
// RETURN:	-1 * v
//
// NOTE:	Use's all four components
TVECTOR Vector_Negate(TVECTOR v)
{
	// TODO LAB 1: Replace with your implementation.
	TVECTOR Temp;
	Temp.x = (v.x * -1);
	Temp.y = (v.y * -1);
	Temp.z = (v.z * -1);
	Temp.w = (v.w * -1);
	return Temp; 
}

// Perform a Dot Product on two TVECTOR's
//
// IN:		v		First Vector. Left Hand Side
//			w		Second Vector. Right Hand Side
//
// RETURN:  v (DOT) w
//
// NOTE:	Use's all four components
float Vector_Dot(TVECTOR v, TVECTOR w)
{
	// TODO LAB 1: Replace with your implementation.
	float Temp;
	Temp = (v.x * w.x);
	Temp += (v.y * w.y);
	Temp += (v.z * w.z);
	Temp += (v.w * w.w);
	return Temp;
}

// Perform a Cross Product on two TVECTOR's
//
// IN:		v		First Vector. Left Hand Side
//			w		Second Vector. Right Hand Side
//
// RETURN:  v (CROSS) w
//
// NOTE:	The w-component of each vector is not used.
//			The resultant vector will have a w-component of zero.
TVECTOR Vector_Cross(TVECTOR v, TVECTOR w)
{
	// TODO LAB 1: Replace with your implementation.
	TVECTOR Temp;
	Temp.x = (v.y * w.z - v.z * w.y);
	Temp.y = (v.z * w.x - v.x * w.z);
	Temp.z = (v.x * w.y - v.y * w.x);
	Temp.w = 0;
	return Temp;
}

// Find the squared length of a TVECTOR
//
// IN:		v		The vector to find the squared length of
//
// RETURN:	Squared Length of TVECTOR
//
// NOTE:	Use's all four components
float Vector_LengthSq(TVECTOR v)
{
	// TODO LAB 1: Replace with your implementation.
	float Mag;
	Mag = (v.x * v.x);
	Mag += (v.y * v.y);
	Mag += (v.z * v.z);
	Mag += (v.w * v.w);
	return Mag;
}

// Find the length of a TVECTOR
//
// IN:		v		The vector to find the length of
//
// RETURN:	Length of TVECTOR
//
// NOTE:	Use's all four components
float Vector_Length(TVECTOR v)
{
	// TODO LAB 1: Replace with your implementation.
	float Temp;
	Temp = sqrt(Vector_LengthSq(v));
	return Temp;
}

// Normalize a TVECTOR
//
// IN:		v		The vector to normalize
//
// RETURN:	Normalized version of v
//
// NOTE:	Use's all four components
TVECTOR Vector_Normalize(TVECTOR v)
{
	// TODO LAB 1: Replace with your implementation.
	TVECTOR Temp;	
	if (Vector_Length(v) == 0)
	{
		Temp.x = 0;
		Temp.y = 0;
		Temp.z = 0;
		Temp.w = 0;
		return Temp;
	}
	float fTemp = Vector_Length(v);

	Temp.x = (v.x / fTemp);
	Temp.y = (v.y / fTemp);
	Temp.z = (v.z / fTemp);
	Temp.w = (v.w / fTemp);
	return Temp; 

}

// Makes a TVECTOR's w-component normalized
//
// IN:		v		The vector (point object) to homogenise
//
// RETURN:	The homogenised vector (point)
//
// NOTE:	If the w-component of the vector is 0 then the
//			function will return a zero vector with a w-component
//			of 0.
TVECTOR Vector_Homogenise(TVECTOR v)
{
	// TODO LAB 1: Replace with your implementation.
	TVECTOR Temp;
	if (IsZero(v.w))
	{
		Temp.x = 0;
		Temp.y = 0;
		Temp.z = 0;
		Temp.w = 0;
		return Temp;
	}
	Temp.x = (v.x / v.w);
	Temp.y = (v.y / v.w);
	Temp.z = (v.z / v.w);
	Temp.w = (v.w / v.w);
	return Temp;
}

// Get a TVECTOR made from the maximun components of two TVECTORs
//
// IN:		v		The first vector
//			w		The second vector
//
// RETURN:	A maximized vector
//
// NOTE:	Use's all four components
TVECTOR Vector_Maximize(TVECTOR v, TVECTOR w)
{
	// TODO LAB 1: Replace with your implementation.
	TVECTOR Temp;
	Temp.x = Max(v.x,w.x);
	Temp.y = Max(v.y,w.y);
	Temp.z = Max(v.z,w.z);
	Temp.w = Max(v.w,w.w);
	return Temp;
}

// Get a TVECTOR made from the minimum components of two TVECTOR's
//
// IN:		v		The first vector
//			w		The second vector
//
// RETURN:	A minimum vector
//
// NOTE:	Use's all four components
TVECTOR Vector_Minimize(TVECTOR v, TVECTOR w)
{
	// TODO LAB 1: Replace with your implementation.
	TVECTOR Temp;
	Temp.x = Min(v.x,w.x);
	Temp.y = Min(v.y,w.y);
	Temp.z = Min(v.z,w.z);
	Temp.w = Min(v.w,w.w);
	return Temp;
}

// Get a TVECTOR made from the average of two TVECTORs
//
// IN:		v		The first vector
//			w		The second vector
//
// RETURN:	A vector made from the average of two vectors
//
// NOTE:	Use's all four components

TVECTOR Vector_Average(TVECTOR v, TVECTOR w)
{
	// TODO LAB 1: Replace with your implementation.
	TVECTOR Temp;
	Temp.x = ((v.x + w.x)*(.5));
	Temp.y = ((v.y + w.y)*(.5));
	Temp.z = ((v.z + w.z)*(.5));
	Temp.w = ((v.w + w.w)*(.5));
	return Temp;
}

// Find the angle between two TVECTORs
//
// IN:		v		The first vector
//			w		The second vector
//
// RETURN:  The angle in degrees between the two vectors
//
// NOTE:	If either vector is a zero vector then the return
//			value will be 0.
float Vector_AngleBetween(TVECTOR v, TVECTOR w)
{
	// TODO LAB 1: Replace with your implementation.
	if (IsZero(v.x) || IsZero(v.y) || IsZero(v.z))
		return 0;
	else if (IsZero(w.x) || IsZero(w.y) || IsZero(w.z))
		return 0;
	else
	{
		float Angle = acosf(Vector_Dot(v,w)/(Vector_Length(v) * Vector_Length(w)));
		Angle = Radians_To_Degrees(Angle);
		return Angle;
	}
	return 0;
}

// Get the distance one TVECTOR points in the direction of another
// TVECTOR
//
// IN:		v		The first vector
//			w		The direction of the component
//
// RETURN:	The distance that v points in the direction of w.
//
// NOTE:	If w or v is a zero vector then the return value is zero.
float Vector_Component(TVECTOR v, TVECTOR w)
{
	// TODO LAB 1: Replace with your implementation.
	if (IsZero(v.x) && IsZero(v.y) && IsZero(v.z))
		return 0;
	if (IsZero(w.x) && IsZero(w.y) && IsZero(w.z))
		return 0;
	return Vector_Dot(v,Vector_Normalize(w));
}

// Get the TVECTOR that represents v projected on w.
//
// IN:		v		The first vector
//			w		The direction of the projection
//
// RETURN:	The projection of v onto w
//
// NOTE:	If w or v is a zero vector then the return value is zero.
TVECTOR Vector_Project(TVECTOR v, TVECTOR w)
{
	// TODO LAB 1: Replace with your implementation.
	float fTemp = Vector_Component(v,w);
	TVECTOR Temp = Vector_Normalize(w);
	Temp.x *= fTemp;
	Temp.y *= fTemp;
	Temp.z *= fTemp;
	Temp.w *= fTemp;
	return Temp;
}

////////////////////////////////////////////////////////////////////////
// Functions Lab  #2
///////////////////////////////////////////////////////////////////////


// Get the reflection of v across w
//
// IN:		v		The vector to reflect
//			w		The "axis" to reflect across
//
// RETURN:	v reflected across w
//
// NOTE:	If w is a zero vector then return -v.
TVECTOR Vector_Reflect(TVECTOR v, TVECTOR w)
{
	// TODO LAB 2: Replace with your implementation.
if(Vector_Length(w))
	return Vector_Sub(Vector_Scalar_Multiply(Vector_Project(v,w),2),v);
else
	return Vector_Negate(v);
}

//////////////////////////////////////////////////////////////////////////
// Matrix Functions
//////////////////////////////////////////////////////////////////////////

// Get a [0] matrix
//
// RETURN: A 0 4x4 matrix
TMATRIX Matrix_Zero(void)
{
	// TODO LAB 2: Replace with your implementation.
	TMATRIX m = {0};

	return m;
}

// Get a [I] matrix
//
// RETURN: A 4x4 Identity matrix
TMATRIX Matrix_Identity(void)
{
	// TODO LAB 2: Replace with your implementation.
	TMATRIX m = { 1,0,0,0,
				  0,1,0,0,
				  0,0,1,0,
				  0,0,0,1};
	return m;
}

// Get a translation matrix
//
// IN:		x		Amount of translation in the x direction
//			y		Amount of translation in the y direction
//			z		Amount of translation in the z direction
//
// RETURN:	The translation matrix
TMATRIX Matrix_Create_Translation(float x, float y, float z)
{
	// TODO LAB 2: Replace with your implementation.
	TMATRIX m = { 1,0,0,x,
				  0,1,0,y,
				  0,0,1,z,
				  0,0,0,1,};
	return m;
}

// Create a scale matrix
//
// IN:		x		Amount to scale in the x direction
//			y		Amount to scale in the y direction
//			z		Amount to scale in the z direction
//
// RETURN:	The scale matrix
TMATRIX Matrix_Create_Scale(float x, float y, float z)
{
	// TODO LAB 2: Replace with your implementation.
	TMATRIX m = { 	x,0,0,0,
					0,y,0,0,
					0,0,z,0,
					0,0,0,1};
	return m;
}

// Get a rotation matrix for rotation about the x-axis
//
// IN:		Deg		Angle to rotate ( Degree measure)
//
// RETURN:	A X-Rotation Matrix
TMATRIX Matrix_Create_Rotation_X(float Deg)
{
	// TODO LAB 2: Replace with your implementation.
	TMATRIX m = { 	1,0,0,0,
					0,cos(Degrees_To_Radians(Deg))	,-sin(Degrees_To_Radians(Deg)),	0,
					0,sin(Degrees_To_Radians(Deg))	,cos(Degrees_To_Radians(Deg)),	0,
					0,0,							0,								1};
	return m;
}

// Get a rotation matrix for rotation about the y-axis
//
// IN:		Deg		Angle to rotate ( Degree measure)
//
// RETURN:	A Y-Rotation Matrix
TMATRIX Matrix_Create_Rotation_Y(float Deg)
{
	// TODO LAB 2: Replace with your implementation.
	TMATRIX m = { 	cos(Degrees_To_Radians(Deg)),	0,	sin(Degrees_To_Radians(Deg)),	0,
					0,								1,	0,								0,
					-sin(Degrees_To_Radians(Deg)),	0,	cos(Degrees_To_Radians(Deg)),	0,
					0,								0,	0,								1};
	return m;
}

// Get a rotation matrix for rotation about the z-axis
//
// IN:		Deg		Angle to rotate ( Degree measure)
//
// RETURN:	A Z-Rotation Matrix
TMATRIX Matrix_Create_Rotation_Z(float Deg)
{
	// TODO LAB 2: Replace with your implementation.
	TMATRIX m = { 	cos(Degrees_To_Radians(Deg)),	-sin(Degrees_To_Radians(Deg)),	0,	0,
					sin(Degrees_To_Radians(Deg)),	cos(Degrees_To_Radians(Deg)),	0,	0,
					0,								0,								1,	0,
					0,								0,								0,	1};
	return m;
}

// ADD two matrices together
//
// IN:		m		The first matrix
//			n		The second matrix
//
// RETURN: m + n
TMATRIX Matrix_Matrix_Add(TMATRIX m, TMATRIX n)
{
	// TODO LAB 2: Replace with your implementation.
	TMATRIX Temp = {m._e11 + n._e11,	m._e12 + n._e12,	m._e13 + n._e13,	m._e14 + n._e14,
					m._e21 + n._e21,	m._e22 + n._e22,	m._e23 + n._e23,	m._e24 + n._e24,
					m._e31 + n._e31,	m._e32 + n._e32,	m._e33 + n._e33,	m._e34 + n._e34,
					m._e41 + n._e41,	m._e42 + n._e42,	m._e43 + n._e43,	m._e44 + n._e44};

	return Temp;
}

// SUBTRACT two matrices
//
// IN:		m		The first matrix (left hand side)
//			n		The second matrix (right hand side)
//
// RETURN: m - n
TMATRIX Matrix_Matrix_Sub(TMATRIX m, TMATRIX n)
{
	// TODO LAB 2: Replace with your implementation.
	TMATRIX Temp = {m._e11 - n._e11,	m._e12 - n._e12,	m._e13 - n._e13,	m._e14 - n._e14,
					m._e21 - n._e21,	m._e22 - n._e22,	m._e23 - n._e23,	m._e24 - n._e24,
					m._e31 - n._e31,	m._e32 - n._e32,	m._e33 - n._e33,	m._e34 - n._e34,
					m._e41 - n._e41,	m._e42 - n._e42,	m._e43 - n._e43,	m._e44 - n._e44};

	return Temp;
}

// Multiply a matrix by a scalar
//
// IN:		m		The matrix to be scaled (right hand side)
//			s		The value to scale by   (left hand side)
//
// RETURN:	The matrix formed by s*[m]
TMATRIX Matrix_Scalar_Multiply(TMATRIX m, float s)
{
	// TODO LAB 2: Replace with your implementation.
	for (int i = 0; i < 16; i++)
		m.e[i] *= s;
	return m;
}

// Negate a matrix
//
// IN:		m		The matrix to negate
//
// RETURN:  The negation of m
TMATRIX Matrix_Negate(TMATRIX m)
{
	// TODO LAB 2: Replace with your implementation.
	for (int i = 0; i < 16;i++)
		m.e[i] *= (-1);
	return m;
}

// Transpose a matrix
//
// IN:		m		The matrix to transpose
//
// RETURN:	The transpose of m
TMATRIX Matrix_Transpose(TMATRIX m)
{
	// TODO LAB 2: Replace with your implementation.
	TMATRIX Temp = { 	m._e11,m._e21,m._e31,m._e41,
						m._e12,m._e22,m._e32,m._e42,
						m._e13,m._e23,m._e33,m._e43,
						m._e14,m._e24,m._e34,m._e44};
	return Temp;
}

// Multipy a matrix and a vector
//
// IN:		m		The matrix (left hand side)
//			v		The vector (right hand side)
//
// RETURN:	[m]*v
TVECTOR Matrix_Vector_Multiply(TMATRIX m, TVECTOR v)
{
	// TODO LAB 2: Replace with your implementation.
	TVECTOR Temp;
	Temp.x = (m._e11 * v.x + m._e12 * v.y + m._e13 * v.z + m._e14 * v.w);
	Temp.y = (m._e21 * v.x + m._e22 * v.y + m._e23 * v.z + m._e24 * v.w);
	Temp.z = (m._e31 * v.x + m._e32 * v.y + m._e33 * v.z + m._e34 * v.w);
	Temp.w = (m._e41 * v.x + m._e42 * v.y + m._e43 * v.z + m._e44 * v.w);
	return Temp;
}

// Multipy a vector and a matrix
//
// IN:		v		The vector ( left hand side)
//			m		The matrix (right hand side)
//
// RETURN:	v*[m]
TVECTOR Vector_Matrix_Multiply(TVECTOR v, TMATRIX m)
{
	// TODO LAB 2: Replace with your implementation.
	m = Matrix_Transpose(m);
		TVECTOR Temp;
	Temp.x = (m._e11 * v.x + m._e12 * v.y + m._e13 * v.z + m._e14 * v.w);
	Temp.y = (m._e21 * v.x + m._e22 * v.y + m._e23 * v.z + m._e24 * v.w);
	Temp.z = (m._e31 * v.x + m._e32 * v.y + m._e33 * v.z + m._e34 * v.w);
	Temp.w = (m._e41 * v.x + m._e42 * v.y + m._e43 * v.z + m._e44 * v.w);
	return Temp;
}

// Multiply a matrix by a matrix
//
// IN:		m		First Matrix (left hand side)
//			n		Second Matrix (right hand side)
//
// RETURN:	[m]*[n]
TMATRIX Matrix_Matrix_Multiply(TMATRIX m, TMATRIX n)
{
	// TODO LAB 2: Replace with your implementation.
	TMATRIX Temp = {m._e11*n._e11 + m._e12*n._e21 + m._e13*n._e31 + m._e14*n._e41,	m._e11*n._e12 + m._e12*n._e22 + m._e13*n._e32 + m._e14*n._e42,	m._e11*n._e13 + m._e12*n._e23 + m._e13*n._e33 + m._e14*n._e43,	m._e11*n._e14 + m._e12*n._e24 + m._e13*n._e34 + m._e14*n._e44,
					m._e21*n._e11 + m._e22*n._e21 + m._e23*n._e31 + m._e24*n._e41,	m._e21*n._e12 + m._e22*n._e22 + m._e23*n._e32 + m._e24*n._e42,	m._e21*n._e13 + m._e22*n._e23 + m._e23*n._e33 + m._e24*n._e43,	m._e21*n._e14 + m._e22*n._e24 + m._e23*n._e34 + m._e24*n._e44,
					m._e31*n._e11 + m._e32*n._e21 + m._e33*n._e31 + m._e34*n._e41,	m._e31*n._e12 + m._e32*n._e22 + m._e33*n._e32 + m._e34*n._e42,	m._e31*n._e13 + m._e32*n._e23 + m._e33*n._e33 + m._e34*n._e43,	m._e31*n._e14 + m._e32*n._e24 + m._e33*n._e34 + m._e34*n._e44,
					m._e41*n._e11 + m._e42*n._e21 + m._e43*n._e31 + m._e44*n._e41,	m._e41*n._e12 + m._e42*n._e22 + m._e43*n._e32 + m._e44*n._e42,	m._e41*n._e13 + m._e42*n._e23 + m._e43*n._e33 + m._e44*n._e43,	m._e41*n._e14 + m._e42*n._e24 + m._e43*n._e34 + m._e44*n._e44};
	return Temp;
}

////////////////////////////////////////////////////////////////////////
// Matrix Functions Lab # 3
///////////////////////////////////////////////////////////////////////

// HELPER FUNCTION  *** NOT GRADED, ONLY SUGGESTED ***
// USE THIS FUNCTION TO FIND THE DETERMINANT OF A 3*3
// MATRIX. IT CAN BE USED IN THE MATRIX DETERMINANT
// AND MATRIX INVERSE FUNCTIONS BELOW
// 
// RETURN:	The determinant of a 3x3 matrix
float Matrix_Determinant(	float e_11,float e_12,float e_13,
							float e_21,float e_22,float e_23,
							float e_31,float e_32,float e_33)
{
	float Temp = ((e_11*(e_22*e_33-e_32*e_23)) - (e_12*(e_21*e_33-e_31*e_23)) + (e_13*(e_21*e_32-e_31*e_22)));
	return Temp;
}

// Get the determinant of a matrix
//
// IN:		m		The ONE!
//
// RETURN:	It's deterinant
float Matrix_Determinant(TMATRIX m)
{
	// TODO LAB 3: Replace with your implementation.
	float Temp;
	Temp = (m._e11*Matrix_Determinant(m._e22,m._e23,m._e24,m._e32,m._e33,m._e34,m._e42,m._e43,m._e44));
	Temp -= (m._e12*Matrix_Determinant(m._e21,m._e23,m._e24,m._e31,m._e33,m._e34,m._e41,m._e43,m._e44));
	Temp += (m._e13*Matrix_Determinant(m._e21,m._e22,m._e24,m._e31,m._e32,m._e34,m._e41,m._e42,m._e44));
	Temp -= (m._e14*Matrix_Determinant(m._e21,m._e22,m._e23,m._e31,m._e32,m._e33,m._e41,m._e42,m._e43));
	return Temp;
}

// Get the inverse of a matrix
//
// IN:		m		The matrix to inverse
//
// RETURN:	The Inverse of [m]
//
// NOTE: Returns the matrix itself if m is not invertable.
TMATRIX Matrix_Inverse(TMATRIX m)
{
	// TODO LAB 3: Replace with your implementation.
	if(Matrix_Determinant(m))
	{
		float DetTemp = Matrix_Determinant(m);
		TMATRIX Temp = 
		{
			Matrix_Determinant(m._e22, m._e23, m._e24, m._e32, m._e33, m._e34, m._e42, m._e43, m._e44) / DetTemp,
			-Matrix_Determinant(m._e21, m._e23, m._e24, m._e31, m._e33, m._e34, m._e41, m._e43, m._e44) / DetTemp,
			Matrix_Determinant(m._e21, m._e22, m._e24, m._e31, m._e32, m._e34, m._e41, m._e42, m._e44) / DetTemp,
			-Matrix_Determinant(m._e21, m._e22, m._e23, m._e31, m._e32, m._e33, m._e41, m._e42, m._e43) / DetTemp,

			-Matrix_Determinant(m._e12, m._e13, m._e14, m._e32, m._e33, m._e34, m._e42, m._e43, m._e44) / DetTemp,
			Matrix_Determinant(m._e11, m._e13, m._e14, m._e31, m._e33, m._e34, m._e41, m._e43, m._e44) / DetTemp,
			-Matrix_Determinant(m._e11, m._e12, m._e14, m._e31, m._e32, m._e34, m._e41, m._e42, m._e44) / DetTemp,
			Matrix_Determinant(m._e11, m._e12, m._e13, m._e31, m._e32, m._e33, m._e41, m._e42, m._e43) / DetTemp,

			Matrix_Determinant(m._e12, m._e13, m._e14, m._e22, m._e23, m._e24, m._e42, m._e43, m._e44) / DetTemp,
			-Matrix_Determinant(m._e11, m._e13, m._e14, m._e21, m._e23, m._e24, m._e41, m._e43, m._e44) / DetTemp,
			Matrix_Determinant(m._e11, m._e12, m._e14, m._e21, m._e22, m._e24, m._e41, m._e42, m._e44) / DetTemp,
			-Matrix_Determinant(m._e11, m._e12, m._e13, m._e21, m._e22, m._e23, m._e41, m._e42, m._e43) / DetTemp,

			-Matrix_Determinant(m._e12, m._e13, m._e14, m._e22, m._e23, m._e24, m._e32, m._e33, m._e34) / DetTemp,
			Matrix_Determinant(m._e11, m._e13, m._e14, m._e21, m._e23, m._e24, m._e31, m._e33, m._e34) / DetTemp,
			-Matrix_Determinant(m._e11, m._e12, m._e14, m._e21, m._e22, m._e24, m._e31, m._e32, m._e34) / DetTemp,
			Matrix_Determinant(m._e11, m._e12, m._e13, m._e21, m._e22, m._e23, m._e31, m._e32, m._e33) / DetTemp
		};

		return Matrix_Transpose(Temp);
	}
	else
		return m;
}

